import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Xml {
    private static final String XML = "<root>"
                                    + "  <users>" +
                                      "    <user name='Ivan' age='25'>" +
                                      "      <address city='Moscow' country='Russia' />" +
                                      "    </user>" +
                                      "    <user name='Helen' age='21'>" +
                                      "      <address city='Paris' country='France' />" +
                                      "    </user>" +                                      
                                      "  </users>" +
                                      "</root>";
        
    public static void main(String[] args) throws Exception {
        //sax();
        //dom();
        //stax();
        //jaxb();
    }
    
    private static void jaxb() throws Exception {
        Root root = (Root) JAXBContext.newInstance(Root.class).createUnmarshaller().unmarshal(new StringReader(XML));
        
        for (User user : root.getUsers()) {
            System.out.println(user.getName());
            System.out.println(user.getAge());
        }
    }
    
    private static void stax() throws Exception {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        
        XMLEventReader r = factory.createXMLEventReader(new StringReader(XML));
        
        while (r.hasNext()) {
            XMLEvent e = r.nextEvent();
            
            if (e.isStartElement()) {
                StartElement s = e.asStartElement();
                
                if (s.getName().getLocalPart().equals("user")) {
                    System.out.println(s.getAttributeByName(QName.valueOf("name")) + ", " + s.getAttributeByName(QName.valueOf("age")));
                }
            }
        }
    }
        
    private static void sax() throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        
        SAXParser p = factory.newSAXParser();
        
        p.parse(new ByteArrayInputStream(XML.getBytes()), new SAXHandler());        
    }
    
    private static void dom() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        
        DocumentBuilder db = dbf.newDocumentBuilder();
        
        Document doc = db.parse(new ByteArrayInputStream(XML.getBytes()));
        
        NodeList userNodes = doc.getElementsByTagName("user");
        
        for (int i = 0; i < userNodes.getLength(); i++) {
            Node userNode = userNodes.item(i);
            
            System.out.println(userNode.getAttributes().getNamedItem("name"));
            System.out.println(userNode.getAttributes().getNamedItem("age"));            
        }
    }
}

class SAXHandler extends DefaultHandler {
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println("Start: " + qName);        
    }    
    
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("End: " + qName);
    }
}

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
class Root {
    @XmlElementWrapper
    @XmlElement(name = "user")
    private List<User> users = new ArrayList<>();

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
class User {
    @XmlAttribute
    private String name;
    
    @XmlAttribute
    private int age;
    
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
class Address {
    private String city;
    
    private String country;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }
}